package org.twdata.pipeline.stage;

import java.io.IOException;
import java.io.Reader;
import java.io.InputStream;
import javax.xml.parsers.*;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

import org.twdata.pipeline.*;

// SAX imports:
import org.xml.sax.*;
import org.xml.sax.ext.LexicalHandler;

/**
 *  Generates SAX events by parsing the reader using the JAXP API. Requires
 *  well-formed XML content
 */
public class JAXPGenerator implements Generator {

    private XMLReader parser = null;
    private Reader reader;
    private InputStream stream;
    private String id;


    /**
     *  Sets up the instance for the current context.  Initializes the parser
     *  if necessary.
     *
     *@param  ctx                    The transform context
     *@exception  PipelineException  If anything goes wrong
     */
    public void setup(PipelineContext ctx)
        throws PipelineException {
        
        if (parser == null) {
            parser = createXMLReader();
        }
        Source src = ctx.getSource();
        if (src instanceof StreamSource) {
            StreamSource source = (StreamSource)src;
            reader = source.getReader();
            if (reader == null) {
                stream = source.getInputStream();
            }
        } else {
            throw new PipelineException("Source type not supported");
        }
    }


    /**  Recycles the instance */
    public void recycle() {
        reader = null;
        stream = null;
    }


    /**
     *  Gets the id
     *
     *@return    The id value
     */
     public String getId() {
        return id;   
     }
    
    /**
     *  Sets the id
     *
     *@param  id  The unique id
     */
     public void setId(String id) {
         this.id = id;
     }


    /**
     *  Generates SAX events by parsing the reader
     *
     *@exception  PipelineException  If anything goes wrong
     */
    public void generate()
        throws PipelineException {
        try {
            if (reader != null) {
                parser.parse(new InputSource(reader));
            } else {
                parser.parse(new InputSource(stream));
            }    
        } catch (Exception ex) {
            throw new PipelineException(ex);
        }
    }


    /**
     *  Sets the consumer to publish XML SAX events to
     *
     *@param  consumer               The new consumer
     *@exception  PipelineException  If anything goes wrong
     */
    public void setConsumer(XMLConsumer consumer)
        throws PipelineException {
        parser.setContentHandler(consumer);
        try {
            parser.setProperty("http://xml.org/sax/properties/lexical-handler", consumer);
        } catch (Exception ex) {
            throw new PipelineException(ex);
        }
    }
    
    protected XMLReader createXMLReader() throws PipelineException {
        XMLReader reader = null;
        try {
             SAXParserFactory pfactory = SAXParserFactory.newInstance();
             pfactory.setNamespaceAware(true);
             parser = pfactory.newSAXParser().getXMLReader();
        } catch (Exception ex) {
            throw new PipelineException(ex);
        }
        return parser;
    }

}

